package roborally;


import java.awt.IllegalComponentStateException;

import be.kuleuven.cs.som.annotate.Basic;

/**
 * A class of carryables, that extends the class placeable. Carryables have 2 booleans (isBeingCarried and isUsable) and a weight.
 * 
 * @invar  | Weight.isValidWeight(this.getWeight())
 * 
 * @version  2.90
 * @author   Michiel Ruelens & Dieter Naten
 */
public class Carryable extends Placeable {

	private boolean isBeingCarried;
	private boolean isUseable;
	private Weight weight;
	private final WeightUnit standardWeightUnit = WeightUnit.GRAM;
	private static final int standardWeightNumeral = 1000;

	/**
     * Initialize the new carryable.
     * 
     * @param  weight
     * 		   The weight of the new battery.
     * @effect  | setCarryStatus(false)
     * @effect  | setUseableStatus(true)
     * @effect  | setWeight(new Weight(weight,standardWeightUnit))
     */
	public Carryable(int weight){
		if(!Weight.isValidWeight(weight,standardWeightUnit)){
			weight = standardWeightNumeral;
			System.out.println("Something went wrong. Remember: a weight cannot be negative.");
			System.out.println("The weight has been placed to the standardWeightNumeral " + standardWeightNumeral);
		}
		setCarryStatus(false);
		setUseableStatus(true);
		setWeight(new Weight(weight,standardWeightUnit));
	}
	
	/**
	 * Terminate this carryable
	 * 
	 * @effect	if(!this.isTerminated() && this.getCarryStatus()==true)
	 * 				{super.terminate()
	 *				 this.setCarryStatus(false)}
	 * @effect if(!this.isTerminated() && this.getCarryStatus()==false)
	 * 				{super.terminate() }		
	 */
	@Override
	public void terminate(){
		if(!this.isTerminated()){
			//Carryable being carried
			if(this.getCarryStatus()){
				super.terminate();
				this.setCarryStatus(false);
			}
			//Else the carryable is on a board
			else{
				super.terminate();
			}
		}
		else{
			System.out.println("That carryable has already been terminated.");
		}
	}
	
	/**
	 * This method will return the board on which this carryable is placed.
	 */
	@Basic
	@Override
	public Board getBoard(){
		if(getCarryStatus()!=true)
			return super.getBoard();
		else{
			System.out.println("This carryable is being carried");
			return null;
		}
	}
	
	/**
	 * This method will return x-coordinate of the carryable.
	 */
	@Basic
	@Override
	public long getX() {
		if(getCarryStatus()!=true)
			return super.getX();
		else{
			return -1;
		}
	}
	
	/**
	 * This method will return y-coordinate of the carryable.
	 */
	@Basic
	@Override
	public long getY() {
		if(getCarryStatus()!=true)
			return super.getY();
		else{
			return -1;
		}
	}


	/**
	 * This method will return the value of isBeingCarried of this carryable.
	 */
	@Basic
	public boolean getCarryStatus(){
		return isBeingCarried;
	}
	
	/**
     * Set the boolean isBeingCarried to the given status.
     * 
     * @param status
     *        The status on which the boolean isBeingCarried should be placed
     * @post  | (new this).getCarryStatus == status
     */
	public void setCarryStatus(boolean status){
		this.isBeingCarried = status;
	}
	
	/**
	 * This method will return the value of isUsable of this carryable.
	 */
	@Basic
	public boolean isUseable() {
		return isUseable;
	}

	/**
     * Set the boolean isUseable to the given status.
     * 
     * @param status
     *        The status on which the boolean isUsable should be placed
     * @post  | (new this).isUseable() == status
     */
	public void setUseableStatus(boolean isUseable) {
		this.isUseable = isUseable;
	}
	
	/**
	 * Get the weight of this battery.
	 */
	@Basic
	public Weight getWeight() {
		return weight;
	}
	
	/**
	 * This method sets the weight of a battery to the given weight.
	 * 
	 * @param 	weight
	 * 			The weight this battery is to be given.
	 * @post	(new this).getWeight() == weight
	 */
	public void setWeight(Weight weight) {
		if(Weight.isValidWeight(weight.getNumeral(), weight.getUnit())){ 
			this.weight = weight;	
		}
		else{ 
			System.out.println("Something went wrong. Remember: a weight cannot be negative.");
		}
	}
	
	/**
	 * This method is executed when the given robot wants to use the current carryable. 
	 * This method must be overriden by subclasses that are useable, otherwise the carryable is not useable and an exception is thrown,
	 * because the carryable shouldn't have been used. Normally this exception should never be thrown as robot checks whether the carryable
	 * is useable or not, before using it.
	 * 
	 * @param 	robot
	 * 			The robot that wants to use the current carryable.
	 * @throws 	IllegalStateException
	 * 			This exception is thrown when the current carryable can't be used, see method doc header for more information.
	 */
	public void useCarryable(Robot robot) throws IllegalStateException {
		/*THIS METHOD MUST BE OVERRIDDEN BY SUBCLASSES THAT ARE USEABLE
		* OTHERWISE THE CARRYABLE IS NOT USEABLE AND AN EXCEPTION IS THROWN
		* BECAUSE THAT CARRYABLE SHOULDN'T HAVE NEEN USED.
		* NORMALLY THIS EXCEPTION SHOULD NEVER BE THROWN AS ROBOT CHECKS
		* WHETHER THE CARRYABLE IS USEABLE OR NOT BEFORE USING IT.
		*/
		System.out.println("That carryable cannot be used. An exception will be thrown because you've reached a point in the program where you shouldn't be.");
		throw new IllegalStateException();
	}
}
